//
//  BCBaseWebViewController.m
//  GSBlockChain
//
//  Created by guoshikeji_a on 2018/11/28.
//  Copyright © 2018 guoshikeji. All rights reserved.
//

#import "BCBaseWebViewController.h"

#import "YLProgressBar.h"

#import "NSError+HttpRequest.h"



//监听webview title 变化
NSString *const WKWebViewTitle = @"title";
//监听webview progress 变化
NSString *const WKWebViewEstimateProgess = @"estimatedProgress";

@interface BCBaseWebViewController (){
    YLProgressBar *_progressBar;
}

@end

@implementation BCBaseWebViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];
    [self initWebView];
    [self initScriptMessageHandler];
    [self addBaseKVO];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
#pragma mark - Views
/**
 *初始化webView
 */
- (void)initWebView {
    if (!_webView) {
        WKWebViewConfiguration *webViewConfiguration = [[WKWebViewConfiguration alloc] init];
        // 默认为0
        webViewConfiguration.preferences.minimumFontSize = 10.0f;
        // 默认认为YES
        webViewConfiguration.preferences.javaScriptEnabled = YES;
        // 在iOS上默认为NO，表示不能自动通过窗口打开
        webViewConfiguration.preferences.javaScriptCanOpenWindowsAutomatically = true;
        //允许视频不全屏播放
        webViewConfiguration.allowsInlineMediaPlayback = YES;
        //
        WKUserContentController *webViewUserContent = [[WKUserContentController alloc] init];
        //
        webViewConfiguration.userContentController = webViewUserContent;
        _webView = [[BCWebView alloc] initWithFrame:CGRectZero configuration:webViewConfiguration];
        _webView.UIDelegate = self;
        _webView.navigationDelegate = self;
        _webView.allowsLinkPreview = false;
        //允许手势返回
        _webView.allowsBackForwardNavigationGestures = YES;
        [self.view addSubview:_webView];
        [_webView mas_makeConstraints:^(MASConstraintMaker *make) {
            if (@available(iOS 11.0,*)) {
                make.left.mas_equalTo(self.view.mas_safeAreaLayoutGuideLeft);
                make.top.mas_equalTo(self.customNaviBar.mas_bottom);
                make.width.mas_equalTo(self.view);
                make.bottom.mas_equalTo(self.view.mas_safeAreaLayoutGuideBottom);
            }else {
                make.left.mas_equalTo(self.view);
                make.top.mas_equalTo(self.customNaviBar.mas_bottom);
                make.width.mas_equalTo(self.view);
                make.height.mas_equalTo(self.view);
            }
        }];
        
        //
        _progressBar = [[YLProgressBar alloc] init];
        _progressBar.type = YLProgressBarTypeFlat;
        _progressBar.trackTintColor = [UIColor clearColor];
        _progressBar.progressStretch = NO;
        _progressBar.progressTintColor = [UIColor darkMainColor];
        //_progressBar.stripesColor = DC_THEME_COLOR;
        _progressBar.uniformTintColor = YES;
        [_webView addSubview:_progressBar];
        [_progressBar mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.left.right.equalTo(self.webView);
            make.height.equalTo(@(2.0f));
        }];
    }
    [self.view layoutIfNeeded];
    [_progressBar setProgress:0 animated:NO];
}

#pragma mark - handlers
- (void)initScriptMessageHandler {
    if (!_scriptMessageHandler) {
        _scriptMessageHandler = [BCScriptMessageHandler scriptMessageHandlerDelegate:self];
    }
}


#pragma mark - KVO
- (void)addBaseKVO {
    //KVO 监听 3 个属性 title loading estimatedProgress
    if (_webView) {
        [_webView addObserver:self forKeyPath:WKWebViewTitle options:NSKeyValueObservingOptionNew context:nil];
        [_webView addObserver:self forKeyPath:WKWebViewEstimateProgess options:NSKeyValueObservingOptionNew context:nil];
    }
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:WKWebViewTitle]) {
        [self baseSetTtileAction];
    }
    if ([keyPath isEqualToString:WKWebViewEstimateProgess]) {
        [_progressBar setProgress:_webView.estimatedProgress animated:YES];
    }
}


#pragma mark - WKNavigationDelegate
// 决定导航的动作，通常用于处理跨域的链接能否导航。WebKit对跨域进行了安全检查限制，不允许跨域，因此我们要对不能跨域的链接
// 单独处理。但是，对于Safari是允许跨域的，不用这么处理。
// 这个是决定是否Request
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    //
    /*
     NSURLRequest *request = navigationAction.request;
     NSLog(@"to url:%@", request.URL.absoluteString);
     //需要对跨域做单独处理 默认http 和 https 不做跨域处理
     NSString *scheme = request.URL.scheme;
     if (![scheme isEqualToString:@"http"] && ![scheme isEqualToString:@"https"]) {
     //检测 妈蛋 要面对各种情况 phoneto://095196166
     
     
     decisionHandler(WKNavigationActionPolicyCancel);
     }
     decisionHandler(WKNavigationActionPolicyAllow);
     */
    WEAK_SELF
    WKNavigationActionPolicy policy = [WKWbCrossDomainHandle crossDomainHandleWebView:webView decidePolicyForNavigationAction:navigationAction useRequest:^(NSURLRequest *request) {
        wself.currentRequest = request;
    }];
    decisionHandler(policy);
}
// 决定是否接收响应
// 这个是决定是否接收response
// 要获取response，通过WKNavigationResponse对象获取
/*
 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
 
 
 decisionHandler(WKNavigationResponsePolicyAllow);
 }
 */

// 当main frame的导航开始请求时，会调用此方法
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation {
    //[AKHUD showCarLoadingHUD:self.webView];
}

// 当main frame接收到服务重定向时，会回调此方法

- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation {
    
}

// 当main frame开始加载数据失败时，会回调
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
    //[AKHUD hideCarLoadingHUD:self.webView];
    //    [self webViewLoadError:webView navigation:navigation withError:error];
    if (error) {
        NSURLSessionDataTask *dataTask;
        NSError *handleError = [NSError handleAFErrorWithDataTask:dataTask error:error];
        NSString *errMsg = handleError.domain;
        if (self.view) {
            [QMUITips showError:errMsg inView:self.view hideAfterDelay:[QMUITips smartDelaySecondsForTipsText:errMsg]];
        }
    }
}
// 当main frame的web内容开始到达时，会回调
/*
 - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation {
 
 }
 */
// 当main frame导航完成时，会回调
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
    //[AKHUD hideCarLoadingHUD:self.webView];
    [self baseSetTtileAction];
}
// 当main frame最后下载数据失败时，会回调
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
    //[AKHUD hideCarLoadingHUD:self.webView];
    //    [self webViewLoadError:webView navigation:navigation withError:error];
}
// 这与用于授权验证的API，与AFN、UIWebView的授权验证API是一样的
/*
 - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *__nullable credential))completionHandler{
 
 }
 */
// 当web content处理完成时，会回调
/*
 - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView NS_AVAILABLE(10_11, 9_0) {
 
 }
 */

#pragma mark - WKUIDelegate
// 创建新的webview
// 可以指定配置对象、导航动作对象、window特性
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
    //好像这里可以处理跨域问题
    NSURL *url = navigationAction.request.URL;
    if (url&&[[UIApplication sharedApplication] canOpenURL:url]) {
        if (@available(iOS 10.0,*)) {
            [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
        }else {
            [[UIApplication sharedApplication] openURL:url];
        }
    }
    return nil;
}
// webview关闭时回调
- (void)webViewDidClose:(WKWebView *)webView NS_AVAILABLE(10_11, 9_0) {
    
}
// 调用JS的alert()方法 必须处理不然会崩溃
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:message preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *action = [UIAlertAction actionWithTitle:BCLocalizedKey(@"general_done") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }];
    [alert addAction:action];
    [self presentViewController:alert animated:YES completion:nil];
}
// 调用JS的confirm()方法 必须处理不然会崩溃
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:message preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *action = [UIAlertAction actionWithTitle:BCLocalizedKey(@"general_done") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(true);
    }];
    [alert addAction:action];
    [alert addAction:[UIAlertAction actionWithTitle:BCLocalizedKey(@"general_cancel") style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(false);
    }]];
    [self presentViewController:alert animated:YES completion:nil];
}
// 调用JS的prompt()方法 必须处理不然会崩溃
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:prompt message:defaultText preferredStyle:UIAlertControllerStyleAlert];
    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        
    }];
    UIAlertAction *action = [UIAlertAction actionWithTitle:BCLocalizedKey(@"general_done") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(alert.textFields[0].text);
    }];
    [alert addAction:action];
    [self presentViewController:alert animated:YES completion:nil];
}


#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    NSLog(@"message.name:\n%@\nmessage.body:\n%@\n",message.name,message.body);
}




#pragma mark - private method
/**
 * 直接加载URL
 */
- (void)loadRequestWithURL:(NSURL *)url {
    if (_webView) {
        [_webView loadRequest:[NSURLRequest requestWithURL:url]];
    }
}

/**
 set title 的方法
 */
- (void)baseSetTtileAction {
    if (self.navigationController.navigationItem&&!self.navigationController.navigationBar.hidden) {
        //self.navigationItem.title = [webView evaluateJavaScript:@"document.title" completionHandler:nil];
        self.navigationItem.title = self.webView.title;
    }else {
        self.title = self.webView.title;
    }
}



#pragma mark - dealloc
- (void)dealloc {
    //记住移除 所有添加的JS接收对象 不然 handler 无法释放
    
    if (_scriptMessageHandler) {
        _scriptMessageHandler.delegate = nil;
        _scriptMessageHandler = nil;
    }
    if (_webView) {
        _webView.UIDelegate = nil;
        _webView.navigationDelegate = nil;
    }
    @try {
        [_webView removeObserver:self forKeyPath:WKWebViewTitle];
        [_webView removeObserver:self forKeyPath:WKWebViewEstimateProgess];
    } @catch (NSException *exception) {
    } @finally {}
}

@end
